// Copyright 2018-2020 JXMaster. All rights reserved.
/*
* @file Input.hpp
* @author JXMaster
* @date 2019/7/24
*/
#pragma once
#include <Runtime/Name.hpp>
#include <Runtime/Vector.hpp>
#include "IInputDevice.hpp"
#include "IMouse.hpp"
#include "IKeyboard.hpp"
#include "IController.hpp"

#ifndef LUNA_INPUT_API
#define LUNA_INPUT_API
#endif

namespace Luna
{
	//! The Input module  represents the global Input system. The Input system provides access directly to the platform's Input 
	//! device like mouse, keyboard, controller, touch, sensors and so on, it is designed to be working close to the OS layer and does not provide 
	//! high-level abstractions like custom actions, key-mappings and so on.
	//! 
	//! The Input system is formed by three parts: Input device, Input system and Input device event queue, and only the former two parts will be used
	//! in polling mode. The Input device is the "driver" for Input system, it fetches the Input from the underlying system/platform and provides the 
	//! Input data to the user. The Input device must be mounted to the Input system before it can be read by user. The global Input system instance 
	//! keeps a list of all Input devices mounted so that they can be fetched by user. 
	//! 
	//! When the Input system initializes, it automatically detects the underlying system for all available Input devices and mounts 
	//! them to the Input system. Note that the devices the Input system detects is not the physical Input device, but their driver files, 
	//! so for example, the "controller" device will exist in all Windows platforms even though they may not has a real XBOX device controller 
	//! attached to computer, so long as XInput driver library exists. This makes hot plug-in available.
	//! 
	//! The Input system works in two modes: pooling mode and event mode. Pooling mode tracks the state of the Input device, like if the button 
	//! is pressed now, or reads the degree of the pressure value from pen tablet, this is considered to be a "raw Input" mode and can be done 
	//! directly by querying the device for the data. Event mode tracks the state change of the Input device, and sends events if some change has 
	//! happened.
	//! To use event mode, however, the user should create an Input event queue from the supported device, and the event messages are sent to 
	//! the event queue, the user reads and handles the Input based on its own strategy, this is considered to be a "buffered Input" and may have 
	//! some delay between the time the event occurs and the time the user handles the event.
	//! 
	//! Note that since the Input system cannot really accepts hardware interruption to be informed of an Input event (because this is happed in 
	//! kernel space of the operating system), all Input devices are actually fetching Input events from OS in a regular time basis, and 
	//! this is happened when `IInput::update` is called. If the event is not generated by system, but by the device itself (like comparing the 
	//! Input state of this update and last update to determine if it is changed), all state changed between two update calls except the last change
	//! will be ignored. This may cause problems if your program's FPS is really low.
	//! 
	//! Also note that in a regular multi-window system like Windows, Linux or MacOS, two set of Input APIs are provided: one is application-based
	//! and one is window-based. The application-based Input APIs will continue to receive inputs even through all windows of the application is
	//! hided from the screen, and the window-based Input APIs will receive inputs only when the window is foregrounded by user or "capturing" the 
	//! Input devices like mouse or keyboard. All Input devices the Input system natively provides are application-based, and there is usually one 
	//! special Input device registered by the Gfx module called "window" to let user handling events in window-based APIs. In single-window 
	//! systems like most mobile and console systems, application-based and window-based APIs exist but do not differ because one application is 
	//! represented by only one window, and the application does not have permissions to access to the system Input when the application is running in 
	//! background.
	namespace Input
	{
		constexpr Guid input_domain{ "{e9a5a195-73a4-4daa-b07d-9f381a860cbc}" };

		namespace InputError
		{
			//! Failed to read from the device because the specified Input device is not connected.
			LUNA_INPUT_API errcode_t input_device_not_connected();
		}

		//! Updates the state of all Input devices to let them dispatch Input messages to Input handlers.
		LUNA_INPUT_API void update();

		//! Gets a list of all registered Input devices.
		LUNA_INPUT_API Vector<Name> get_devices();

		//! Gets an Input device to read Input events from it.
		LUNA_INPUT_API RP<IInputDevice> get_device(const Name& device_name);

		//! Mounts one device to the Input system. The Input system keeps a strong reference to the Input
		//! system until it is unmounted.
		LUNA_INPUT_API RV mount_device(const Name& device_name, IInputDevice* device);

		//! Unmounts one device from the system.
		LUNA_INPUT_API RV unmount_device(const Name& device_name);
	}
}